﻿using System.Text;
using Aurouscia.TableEditor.Core.Utils;

namespace Aurouscia.TableEditor.Core.Html
{
    public static class AuTableHtmlConvertExtension
    {
        public const string stickyContainAttr = "data-autb-sticky-contain";
        public const string stickyLeftAttr = "data-autb-sticky-left";
        public const string stickyTopAttr = "data-autb-sticky-top";
        public static string ConvertToHtml(this AuTable table, AuTableHtmlConverterOptions? options = null)
        {
            List<AuTableMergeInfo?> mergeInfos = table.Merges?.ToList() ?? new();
            List<CellPos> coveredCells = table.GetCoveredCells();

            StringBuilder sb = new();
            sb.Append("<table");
            if (table.StickyFilledAny())
                sb.Append($" {stickyContainAttr}");
            sb.Append('>');
            if (table.Cells is not null && table.Cells.Count > 0)
            {
                var rowCount = table.GetRowCount();
                var columnCount = table.GetColumnCount();
                for (var r = 0; r < rowCount; r++)
                {
                    sb.Append("<tr>");
                    List<string?>? row = table.Cells[r];
                    if (row is not null)
                    {
                        for (var c = 0; c < columnCount && c < row.Count; c++)
                        {
                            if (coveredCells.Any(x => x.Row == r && x.Col == c))
                                continue;
                            string? cellValue = row[c];
                            string? moreAttrs = null;
                            if (options is not null)
                            {
                                //二者只会执行一个
                                if (options.CellConverterAttr is not null)
                                {
                                    (string tdContent, string tdAttributes) cellConvertRes = options.CellConverterAttr(cellValue);
                                    cellValue = cellConvertRes.tdContent;
                                    moreAttrs = cellConvertRes.tdAttributes;
                                }
                                else if (options.CellConverter is not null)
                                {
                                    cellValue = options.CellConverter(cellValue);
                                }
                            }
                            sb.Append("<td");                            
                            
                            var mergeHead = mergeInfos.FirstOrDefault(x=>x is not null && x.Row==r && x.Col == c);
                            if (mergeHead is not null)
                            {
                                string rowspan = mergeHead.Down > 0 ? $" rowspan=\"{mergeHead.Down + 1}\"" : "";
                                string colspan = mergeHead.Right > 0 ? $" colspan=\"{mergeHead.Right + 1}\"" : "";
                                sb.Append(rowspan);
                                sb.Append(colspan);
                            }
                            
                            var colorHere = table.Colors?.Find(ci => ci is { } && ci.Match(r, c));
                            if (colorHere is { })
                            {
                                bool haveTextColor = !string.IsNullOrWhiteSpace(colorHere.Text);
                                bool haveBgColor = !string.IsNullOrWhiteSpace(colorHere.Bg);
                                if (haveBgColor || haveTextColor)
                                {
                                    sb.Append($" style=\"");
                                    if (haveTextColor)
                                        sb.Append($"color:{colorHere.Text};");
                                    if (haveBgColor)
                                        sb.Append($"background-color:{colorHere.Bg};");
                                    sb.Append('\"');
                                }
                            }
                            
                            var stickyAttr = table.GetStickyAttrOfCell(r, c);
                            if (stickyAttr is { }) {
                                sb.Append(' ');
                                sb.Append(stickyAttr);
                            }

                            if (!string.IsNullOrWhiteSpace(moreAttrs))
                            {
                                sb.Append(' ');
                                sb.Append(moreAttrs);
                            }
                            sb.Append('>');
                            sb.Append(cellValue);
                            sb.Append("</td>");
                        }
                    }
                    sb.Append("</tr>");
                }
            }
            sb.Append("</table>");
            return sb.ToString();
        }
        private static List<CellPos> GetCoveredCells(this AuTable table)
        {
            List<CellPos> res = new();
            if (table.Merges is null)
                return res;
            foreach(var m in table.Merges)
            {
                if (m is null) continue;
                for(int r = m.Row; r <= m.Row + m.Down; r++)
                {
                    for(int c = m.Col; c <= m.Col + m.Right; c++)
                    {
                        if(r == m.Row && c == m.Col) 
                            continue;
                        res.Add(new(r, c));
                    }
                }
            }
            return res;
        }
        private static string? GetStickyAttrOfCell(this AuTable table, int r, int c)
        {
            if (table.Sticky is null)
                return null;
            var si = table.Sticky;
            List<string> attrs = new(2);
            if (si.LeftIdx == c + 1)
            {
                if (si.LeftFromRowIdx <= r + 1)
                    attrs.Add(stickyLeftAttr);
            }
            if (si.TopIdx == r + 1)
            {
                if (si.TopFromColIdx <= c + 1)
                    attrs.Add(stickyTopAttr);
            }
            if(attrs.Count > 0)
                return string.Join(' ', attrs);
            return null;
        }
        private static bool StickyFilledAny(this AuTable table)
        {
            if (table.Sticky is null)
                return false;
            var s = table.Sticky;
            return
                s.LeftIdx > 0 ||
                s.LeftFromRowIdx > 0 ||
                s.TopIdx > 0 ||
                s.TopFromColIdx > 0;
        }
    }
}
